#ifndef __iNScriptTraverser__
#define __iNScriptTraverser__

#include "neiderra/core/Base.h"
#include "neiderra/core/io/IOStream.h"
#include "neiderra/core/io/iStreamable.h"
#include "neiderra/utils/iScopeable.h"

#include <stack>
#include <vector>

namespace neiderra {
	namespace utils {
		namespace script {

				struct nsNode;
				struct nsVar;
				struct nsArg;
				struct nsAArg;
				struct nsExpr;
				struct nsOperand;
				struct nsRef;
				struct nsSelfRef;
				struct nsMethodCall;
				struct nsFCall;
				struct nsFunc;
				struct nsNumber;
				struct nsBlock;
				struct nsRetStmt;
				struct nsVarDec;
				struct nsClass;
				struct nsNodes;
				
				class Symtable;

				class iNScriptTraverser: public Base, public iStreamable
				{
				public:
					iNScriptTraverser(Core* core, Symtable* sym);
					virtual ~iNScriptTraverser();

					// begin traversing from specified node
					virtual void traverseFrom(nsNode*)=0;

				protected:
					Symtable* _symtable;
				};

				// nsAsmGenerator translates nsNodes into NScript Assembler code
				class nsAsmGenerator : public iNScriptTraverser, public iScopeable<unsigned int> {
				public:
					struct ENoFreeRegisters{};
				public:
					nsAsmGenerator(Core* core, Symtable* sym);
					virtual ~nsAsmGenerator();

					virtual void traverseFrom(nsNode*);

					enum TraverseType{
                        TT_NORMAL, 
						TT_GETVALUE
					};

					virtual void traverse(nsNode*, TraverseType t = TT_NORMAL);
					virtual void traverse(nsNodes*, TraverseType t = TT_NORMAL);
					virtual void traverse(nsFunc*, TraverseType t = TT_NORMAL);
					virtual void traverse(nsVar*, TraverseType t = TT_NORMAL);
					virtual void traverse(nsVarDec*, TraverseType t = TT_NORMAL);
					virtual void traverse(nsBlock*, TraverseType t = TT_NORMAL);
					virtual void traverse(nsArg*, TraverseType t = TT_NORMAL);
					virtual void traverse(nsExpr*, TraverseType t = TT_NORMAL);
					virtual void traverse(nsOperand*, TraverseType t = TT_NORMAL);
					virtual void traverse(nsFCall*, TraverseType t = TT_NORMAL);
					virtual void traverse(nsNumber*, TraverseType t = TT_NORMAL);
					virtual void traverse(nsRef*, TraverseType t = TT_NORMAL);
					virtual void traverse(nsMethodCall*, TraverseType t = TT_NORMAL);
					virtual void traverse(nsRetStmt*, TraverseType t = TT_NORMAL);
					virtual void traverse(nsAArg*, TraverseType t = TT_NORMAL);
					virtual void traverse(nsClass*, TraverseType t = TT_NORMAL);
					virtual void traverse(nsSelfRef*, TraverseType t = TT_NORMAL);
				private:
					void traverseParams(nsNodes*);
					
				public:
					enum ScopeTypes {
						SCOPE_FREE,
	  					SCOPE_CLASS,
						SCOPE_LVALUE,
						SCOPE_RETSTMT
					};
					
					void reset();

				protected:
                    
					nsClass* _currentClass;
					nsFunc* _currentFunction;

					inline nsFunc* getCurrentFunction();
					inline nsClass* getCurrentClass();
					inline void setCurrentClass(nsClass*);
					inline void setCurrentFunction(nsFunc*);

					std::vector<ScopeTypes> _scopes;
				private:
					void writeln(const std::string&);
					void writeln(const std::string& cmd, const std::string& comment);
					bool _regs[16];
					
					int find_free_reg();
					bool open_reg(unsigned n);
					bool open_regs(std::vector<unsigned>&);
					bool close_regs(std::vector<unsigned>&);
					bool close_reg(unsigned n);
					int find_reg_for(const std::string&);
					
					unsigned reg_offset; 
			};
		}
	}
}

#endif
